<?php


namespace App\Http\Controllers\Common;

use App\Enums\Common\CodeEnum;
use Endroid\QrCode\Color\Color;
use Endroid\QrCode\Encoding\Encoding;
use Endroid\QrCode\ErrorCorrectionLevel\ErrorCorrectionLevelLow;
use Endroid\QrCode\QrCode;
use Endroid\QrCode\Writer\PdfWriter;
use Endroid\QrCode\Writer\PngWriter;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Redis;
use Intervention\Image\Facades\Image;

class ApiHelper
{

    const CURL_DEBUG = false;

    protected static array $curlOptions = [
        //启用时会将头文件的信息作为数据流输出
        CURLOPT_HEADER => false,
        //禁止 cURL 验证对等证书
        CURLOPT_SSL_VERIFYPEER => false,
        //将会根据服务器返回 HTTP 头中的 "Location: " 重定向
        CURLOPT_FOLLOWLOCATION => true,
        //获取的信息以字符串返回，而不是直接输出
        CURLOPT_RETURNTRANSFER => true,

        //Location重定向最大次数
        CURLOPT_MAXREDIRS => 3,
        ////设置成 2，会检查公用名是否存在，并且是否与提供的主机名匹配，0不检查
        CURLOPT_SSL_VERIFYHOST => 0,
        //允许 cURL 函数执行的最长秒数
        CURLOPT_TIMEOUT => 30,
        //在尝试连接时等待的秒数。设置为0，则无限等待
        CURLOPT_CONNECTTIMEOUT => 30,
        //在HTTP请求中包含一个"User-Agent: "头的字符串
        CURLOPT_USERAGENT => 'HttpClient V1.0',
    ];

    /**
     * Http POST
     *
     * @param string $url 请求url.
     * @param array|string|null $params 参数.
     * @param array $headers 请求头.
     *
     * @return boolean|mixed
     */
    public static function httpPost($url, $params = null, array $headers = [])
    {
        $ch = curl_init();
        curl_setopt_array($ch, self::$curlOptions);
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_POST, true); //HTTP POST
        if (is_string($params) || is_array($params)) {
            is_array($params) && $params = http_build_query($params);
            curl_setopt($ch, CURLOPT_POSTFIELDS, $params);
        }
        $headers && curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
        if (self::CURL_DEBUG) {
            $f = fopen(storage_path('logs/curl-verbose-' . date('Y-m-d') . '.log'), 'w+');
            curl_setopt($ch, CURLOPT_VERBOSE, true);
            curl_setopt($ch, CURLOPT_STDERR, $f);
        }
        $ret = curl_exec($ch);
        if ($errNo = curl_errno($ch)) {
            Log::error('[ApiHelper][httpPost]httpPost failed', [$url, $params, $headers, $errNo, curl_error($ch)]);
            $ret = false;
        }
        curl_close($ch);
        return $ret;
    }


    /**
     *
     * @param $data
     * @param string $message
     * @param int $code
     * @param int $httpCode
     * @return \Illuminate\Http\JsonResponse
     */
    public static function responseSuccess(
        $data,
        $message = '',
        $code = CodeEnum::CODE_SUCCESS,
        $httpCode = Response::HTTP_OK
    )
    {
        $responseData = [];
        $responseData['meta'] = [];
        $responseData['meta']['code'] = $code;
        $responseData['meta']['status'] = $httpCode;
        if (is_object($data)) {
            $data = collect($data)->toArray();
        }

        if (empty($message) && array_key_exists($code, CodeEnum::$errorMessage)) {
            $message = CodeEnum::$errorMessage[$code];
        }

        $responseData['meta']['message'] = $message;

        /**
         * 判断是否有分页
         */
        $responseData['data'] = $data['data'] ?? $data ?? [];

        //转换器-分页数据
        if (!empty($data['meta']['pagination']) && isset($data['meta']['pagination']['links'])) {
            $responseData['data'] = $data['data'];
            $responseData['meta'] = array_merge($responseData['meta'], $data['meta']);
        }
        //laravel-默认分页
        if (isset($data['current_page']) && isset($data['total'])) {
            $responseData['data'] = $data['data'];
            unset($data['data']);
            $responseData['meta']['pagination'] = $data;
        }

        return response()->json($responseData);
    }

    /**
     * @param array $data
     * @param string $message
     * @param int $httpCode
     * @param int $code
     * @return \Illuminate\Http\JsonResponse
     * 返回错误信息
     */

    public static function responseError(
        array  $data = [],
        string $message = '',
        int    $httpCode = CodeEnum::CODE_PARAM_ERR,
        int    $code = CodeEnum::CODE_PARAM_ERR
    ): JsonResponse
    {
        $responseData = [];
        $responseData['meta'] = [];
        if (is_object($data)) {
            $data = collect($data)->toArray();
        }
        if (empty($message) && array_key_exists($code, CodeEnum::$errorMessage)) {
            $message = CodeEnum::$errorMessage[$code];
        }
        $responseData['data'] = $data;
        $responseData['meta']['message'] = $message;
        $responseData['meta']['code'] = $code;
        $responseData['meta']['status'] = $httpCode;
        return response()->json($responseData);

    }

    /**
     * @param $status
     * @param $msg
     * @param $data
     * @desc  返回值判断
     * @return \Illuminate\Http\JsonResponse
     * @author: ckg
     * @Time: 2022/11/12 12:01
     */
    public static function backDataCheck($status, $msg, $data = []): \Illuminate\Http\JsonResponse
    {
        if ($status) {
            return self::responseSuccess($data, $msg);
        }
        return self::responseError($data, $msg);
    }

    /**
     * 生成订单号
     * @param string $prefix
     * @return string
     */
    static public function make_order($prefix = '')
    {
        return ($prefix . date('YmdHis') . str_pad(mt_rand(1, 9999), 4, '0', STR_PAD_LEFT));
    }

    /**
     * 生成code吗
     * @param string $prefix
     * @return string
     */
    static public function make_code($length = 15): string
    {
        $str = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
        $len = strlen($str) - 1;
        $randstr = '';
        for ($i = 0; $i < $length; $i++) {
            $num = mt_rand(0, $len);
            $randstr .= $str[$num];
        }
        return $randstr;
    }


    /**
     * xml 转成 数组
     * @param array $p
     * @return array|mixed
     */
    public static function xmlToArray($p = [])
    {

        if (empty($p)) {
            $data = file_get_contents('php://input');
        } else {
            $data = $p;
        }
        Log::channel('xml')->info('xml回调', ['data' => $data]);
        $jsonxml = json_encode(simplexml_load_string($data, 'SimpleXMLElement', LIBXML_NOCDATA));
        $res_data = json_decode($jsonxml, true);

        return $res_data ?? [];
    }

    /**
     * 微信回调成功返回数据
     * @return string
     */
    static public function return_we_chat_success(): string
    {
        return "<xml>
    <return_code><![CDATA[SUCCESS]]></return_code>
   <return_msg><![CDATA[OK]]></return_msg>
 </xml>";
    }


    /**
     *去掉空值
     * @param $arr
     * @return array|string
     */
    public static function _unsetNull($arr): array|string
    {
        if ($arr !== null) {
            if (is_array($arr)) {
                if (!empty($arr)) {
                    foreach ($arr as $key => $value) {
                        if ($value === null) {
                            $arr[$key] = '';
                        } else {
                            $arr[$key] = self::_unsetNull($value);      //递归再去执行
                        }
                    }
                }
            } else {
                if ($arr === null) {
                    $arr = '';
                }
            }
        } else {
            $arr = '';
        }
        return $arr;
    }


    /**
     *获取地址
     * @param $code
     * @return string
     */
    public static function getAddress($code)
    {
        $file = resource_path() . "/json/address.json";
        $data = file_get_contents($file);
        $data = json_decode($data, true);
        $address = empty($data[$code]) ? "全区域" : $data[$code];
        return $address;
    }


    /**
     * 获取市地址数组
     * @param $province
     * @return string
     */
    public static function getCity($province)
    {
        $file = resource_path() . "/json/district.json";
        $data = file_get_contents($file);
        $data = json_decode($data, true);
        $district = empty($data[$province]) ? "" : $data[$province]['children'];
        return $district;
    }


    /**
     * 获取区地址数组
     * @param $province
     * @param $city
     * @return string
     */
    public static function getDistrict($province, $city)
    {
        $file = resource_path() . "/json/district.json";
        $data = file_get_contents($file);
        $data = json_decode($data, true);
        $district = (empty($data[$province]) && empty($data[$province]['children'][$city])) ? "" : $data[$province]['children'][$city]['children'];
        return $district;
    }

    /**
     * 按key获取redis缓存
     * @param $key
     * @return mixed
     */
    public static function getStrRedisByKey($key)
    {
        if (Redis::exists($key)) {
            return Redis::get($key);
        }
        return false;
    }

    /**
     * 设置key的redis缓存
     * @param string $key
     * @param string $value 存储值
     * @param Integer $ll 有效期
     * @return mixed
     */
    public static function setStrRedisByKey($key, $value, $ll = 0)
    {
        if ($ll > 0) {
            return Redis::setex($key, $value, $ll);
        }
        return Redis::set($key, $value);
    }

    /**
     * @param        $url
     * @param string $method
     * @param null $postFields
     * @param null $header
     *
     * @return mixed
     * @throws Exception
     */
    public static function curl(
        $url,
        $method = 'GET',
        $header = null,
        $postFields = null

    )
    {
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_FAILONERROR, false);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
        curl_setopt($ch, CURLOPT_TIMEOUT, 600);
        if (strlen($url) > 5 && strtolower(substr($url, 0, 5)) == "https") {
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
            curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
        }
        switch ($method) {
            case 'POST':
                curl_setopt($ch, CURLOPT_POST, true);
                if (!empty($postFields)) {
                    if (is_array($postFields)) {
                        $postBodyString = "";
                        $postMultipart = false;
                        foreach ($postFields as $k => $v) {
                            if ("@" != substr($v, 0, 1)) { //判断是不是文件上传
                                $postBodyString .= "$k=" . urlencode($v) . "&";
                            } else { //文件上传用multipart/form-data，否则用www-form-urlencoded
                                $postMultipart = true;
                            }
                        }
                        unset($k, $v);
                        if ($postMultipart) {
                            curl_setopt($ch, CURLOPT_POSTFIELDS, $postFields);
                        } else {
                            curl_setopt(
                                $ch,
                                CURLOPT_POSTFIELDS,
                                substr($postBodyString, 0, -1)
                            );
                        }
                    } else {
                        curl_setopt($ch, CURLOPT_POSTFIELDS, $postFields);
                    }
                }
                break;
            default:
                if (!empty($postFields) && is_array($postFields)) {
                    $url .= (strpos($url, '?') === false ? '?' : '&')
                        . http_build_query($postFields);
                }
                break;
        }

        curl_setopt($ch, CURLOPT_URL, $url);

        if (!empty($header) && is_array($header)) {
            curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
        }
        $response = curl_exec($ch);
        if (curl_errno($ch)) {
            throw new \Exception(curl_error($ch), 0);
        }
        curl_close($ch);

        return $response;
    }

    public static function curl_send($rq)
    {
        $curlHandle = curl_init();
        curl_setopt($curlHandle, CURLOPT_URL, $rq['url']);
        switch (true) {
            case isset($rq['method']) && in_array(strtolower($rq['method']), array('get', 'post', 'put', 'delete', 'head')):
                $method = strtoupper($rq['method']);
                break;
            case isset($rq['data']):
                $method = 'POST';
                break;
            default:
                $method = 'GET';
        }
        $header = isset($rq['header']) ? $rq['header'] : array();
        $header[] = 'Method:' . $method;

        $header[] = "User-Agent:Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; SLCC1; .NET CLR 2.0.50727; .NET CLR 3.0.04506; .NET CLR 3.5.21022; .NET CLR 1.0.3705; .NET CLR 1.1.4322)";
        isset($rq['host']) && $header[] = 'Host:' . $rq['host'];
        curl_setopt($curlHandle, CURLOPT_HTTPHEADER, $header);
        curl_setopt($curlHandle, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($curlHandle, CURLOPT_CUSTOMREQUEST, $method);
        isset($rq['timeout']) && curl_setopt($curlHandle, CURLOPT_TIMEOUT, $rq['timeout']);
        isset($rq['data']) && in_array($method, array('POST', 'PUT')) && curl_setopt($curlHandle, CURLOPT_POSTFIELDS, $rq['data']);

        $ssl = substr($rq['url'], 0, 8) == "https://" ? true : false;
        if (isset($rq['cert'])) {
            curl_setopt($curlHandle, CURLOPT_SSL_VERIFYPEER, true);
            curl_setopt($curlHandle, CURLOPT_CAINFO, $rq['cert']);
            curl_setopt($curlHandle, CURLOPT_SSL_VERIFYHOST, 2);
            if (isset($rq['ssl_version'])) {
                curl_setopt($curlHandle, CURLOPT_SSLVERSION, $rq['ssl_version']);
            } else {
                curl_setopt($curlHandle, CURLOPT_SSLVERSION, 4);
            }
        } else if ($ssl) {
            curl_setopt($curlHandle, CURLOPT_SSL_VERIFYPEER, false);   //true any ca
            curl_setopt($curlHandle, CURLOPT_SSL_VERIFYHOST, 2);       //check only host
            if (isset($rq['ssl_version'])) {
                curl_setopt($curlHandle, CURLOPT_SSLVERSION, $rq['ssl_version']);
            } else {
                curl_setopt($curlHandle, CURLOPT_SSLVERSION, 4);
            }
        }
        $return['content'] = curl_exec($curlHandle);
        $return['result'] = curl_getinfo($curlHandle);
        curl_close($curlHandle);
        return $return;
    }

    public static function createQrCode($url, $route = 'user', $method = 'qrcode', $uuid = 0)
    {
        if ($method == 'qrcode') {
            $baseMpHttpsUrl = config('app.url');
//            $qrcodeUrl = $baseMpHttpsUrl."/qrcode/scan?verification_code=".$ScanCode;
            $writer = new PngWriter();
            $qrCode = QrCode::create($url)
                ->setEncoding(new Encoding('UTF-8'))
                ->setErrorCorrectionLevel(new ErrorCorrectionLevelLow())
                ->setSize(240)
                ->setMargin(0)
                ->setForegroundColor(new Color(0, 0, 0))
                ->setBackgroundColor(new Color(255, 255, 255));
            $result = $writer->write($qrCode);
            $path = '/public/qrcode/' . $route;
            if (!is_dir(base_path() . $path)) {
                mkdir(base_path() . $path, 0777, true);
            }
            $pathImg = "qrcode/" . $route . '/' . md5($url) . ".png";
            $qrCodePath = base_path() . '/public/' . $pathImg;
            $result->saveToFile($qrCodePath);
            return $baseMpHttpsUrl . '/' . $pathImg;
        } elseif ($method == 'applet') {
            $baseMpHttpsUrl = config('app.url');
            $writer = new PngWriter();
            $qrCode = QrCode::create($url)
                ->setEncoding(new Encoding('UTF-8'))
                ->setErrorCorrectionLevel(new ErrorCorrectionLevelLow())
                ->setSize(350)
                ->setMargin(0)
//              ->setRoundBlockSizeMode(new RoundBlockSizeModeMargin())
                ->setForegroundColor(new Color(0, 0, 0))
                ->setBackgroundColor(new Color(255, 255, 255));
            $result = $writer->write($qrCode);
            $path = '/public/qrcode/' . $route.'/' . date('Ymd', time());
            if (!is_dir(base_path() . $path)) {
                mkdir(base_path() . $path, 0777, true);
            }
            $qrCodePath = base_path() . '/public/qrcode/' . $route . '/'.date('Ymd', time()).'/' . $uuid . '.png';
            $result->saveToFile($qrCodePath);
            $baseLayerBgImage = base_path() . '/public/qrcode/bg/bg.jpg';
            $baseImageLayer = Image::make($baseLayerBgImage)->resize('270', '300');
            $qrcodeImageLayer = Image::make($qrCodePath)->resize('270', '270');
            $baseImageLayer->insert($qrcodeImageLayer, 'top-left', 0, 0);
//          $x = 100;
            $len = strlen($uuid);
            $x = 110 - ($len * 4.6);
            $baseImageLayer->text($uuid, $x, 295, function ($font) {
                $font->file(base_path() . '/public/Font-Awesome-master/fonts/msyh.ttc');
                $font->size(25);
                $font->valign('bottom');
                $font->color('#000000');
            });
            $savePath = '/qrcode/' . $route . '/' . date('Ymd', time()) . '/' . md5($uuid). '.png';
            $baseImageLayer->save(base_path() . '/public/' . $savePath);
            if (is_file($qrCodePath)) {
                @unlink($qrCodePath);
            }
            return $baseMpHttpsUrl . $savePath;
        }
    }

    //加密密码
    public static function jm($password)
    {
        return md5(md5($password) . 'YSH' . base64_encode(724));
    }
}
